package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.service.MemberService;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dto.OrderSearchParams;
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.promotion.entity.dos.Pintuan;
import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dto.search.PromotionGoodsSearchParams;
import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum;
import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum;
import cn.lili.modules.promotion.entity.vos.PintuanMemberVO;
import cn.lili.modules.promotion.entity.vos.PintuanShareVO;
import cn.lili.modules.promotion.entity.vos.PintuanVO;
import cn.lili.modules.promotion.mapper.PintuanMapper;
import cn.lili.modules.promotion.service.PintuanService;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import cn.lili.modules.promotion.tools.PromotionTools;
import cn.lili.trigger.enums.DelayTypeEnums;
import cn.lili.trigger.interfaces.TimeTrigger;
import cn.lili.trigger.model.TimeExecuteConstant;
import cn.lili.trigger.model.TimeTriggerMsg;
import cn.lili.trigger.util.DelayQueueTools;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 拼团业务层实现
 *
 * @author Chopper
 * @since 2020/8/21
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class PintuanServiceImpl extends AbstractPromotionsServiceImpl<PintuanMapper, Pintuan>
		implements
			PintuanService {

	/**
	 * 促销商品
	 */
	@Autowired
	private PromotionGoodsService promotionGoodsService;
	/**
	 * 规格商品
	 */
	@Autowired
	private GoodsSkuService goodsSkuService;
	/**
	 * 会员
	 */
	@Autowired
	private MemberService memberService;
	/**
	 * 订单
	 */
	@Autowired
	private OrderService orderService;

	/**
	 * 延时任务
	 */
	@Autowired
	private TimeTrigger timeTrigger;

	/**
	 * RocketMQ
	 */
	@Autowired
	private RocketmqCustomProperties rocketmqCustomProperties;

	/**
	 * 获取当前拼团的会员
	 *
	 * @param pintuanId
	 *            拼图id
	 * @return 当前拼团的会员列表
	 */
	@Override
	public List<PintuanMemberVO> getPintuanMember(String pintuanId) {
		List<PintuanMemberVO> members = new ArrayList<>();
		Pintuan pintuan = this.getById(pintuanId);
		if (pintuan == null) {
			log.error("拼团活动为" + pintuanId + "的拼团活动不存在！");
			return new ArrayList<>();
		}
		OrderSearchParams searchParams = new OrderSearchParams();
		searchParams.setOrderStatus(OrderStatusEnum.PAID.name());
		searchParams.setPromotionId(pintuanId);
		searchParams.setOrderPromotionType(PromotionTypeEnum.PINTUAN.name());
		searchParams.setParentOrderSn("");
		searchParams.setMemberId("");
		List<Order> orders = orderService.queryListByParams(searchParams);
		// 遍历订单状态为已支付，为团长的拼团订单
		for (Order order : orders) {
			Member member = memberService.getById(order.getMemberId());
			PintuanMemberVO memberVO = new PintuanMemberVO(member);
			// 获取已参团人数
			this.setMemberVONum(memberVO, pintuan.getRequiredNum(), order.getSn());
			memberVO.setOrderSn(order.getSn());
			members.add(memberVO);
		}
		return members;
	}

	/**
	 * 查询拼团活动详情
	 *
	 * @param id
	 *            拼团ID
	 * @return 拼团活动详情
	 */
	@Override
	public PintuanVO getPintuanVO(String id) {
		Pintuan pintuan = this.getById(id);
		if (pintuan == null) {
			log.error("拼团活动id[" + id + "]的拼团活动不存在！");
			throw new ServiceException(ResultCode.PINTUAN_NOT_EXIST_ERROR);
		}
		PintuanVO pintuanVO = new PintuanVO(pintuan);
		PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
		searchParams.setPromotionId(pintuan.getId());
		pintuanVO.setPromotionGoodsList(promotionGoodsService.listFindAll(searchParams));
		return pintuanVO;
	}

	/**
	 * 获取拼团分享信息
	 *
	 * @param parentOrderSn
	 *            拼团团长订单sn
	 * @param skuId
	 *            商品skuId
	 * @return 拼团分享信息
	 */
	@Override
	public PintuanShareVO getPintuanShareInfo(String parentOrderSn, String skuId) {
		PintuanShareVO pintuanShareVO = new PintuanShareVO();
		pintuanShareVO.setPintuanMemberVOS(new ArrayList<>());
		// 查找团长订单和已和当前拼团订单拼团的订单
		List<Order> orders = orderService.queryListByPromotion(PromotionTypeEnum.PINTUAN.name(),
				PayStatusEnum.PAID.name(), parentOrderSn, parentOrderSn);
		this.setPintuanOrderInfo(orders, pintuanShareVO, skuId);
		// 如果为根据团员订单sn查询拼团订单信息时，找到团长订单sn，然后找到所有参与到同一拼团的订单信息
		if (!orders.isEmpty() && pintuanShareVO.getPromotionGoods() == null) {
			List<Order> parentOrders = orderService.queryListByPromotion(PromotionTypeEnum.PINTUAN.name(),
					PayStatusEnum.PAID.name(), orders.get(0).getParentOrderSn(), orders.get(0).getParentOrderSn());
			this.setPintuanOrderInfo(parentOrders, pintuanShareVO, skuId);
		}
		return pintuanShareVO;
	}

	/**
	 * 更新促销状态 如果要更新促销状态为关闭，startTime和endTime置为空即可
	 *
	 * @param ids
	 *            促销id集合
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return 是否更新成功
	 */
	@Override
	public boolean updateStatus(List<String> ids, Long startTime, Long endTime) {
		if (startTime != null && endTime != null) {
			for (String id : ids) {
				Pintuan pintuan = this.getById(id);
				QueryWrapper<Pintuan> queryWrapper = PromotionTools.checkActiveTime(new Date(startTime),
						new Date(endTime), PromotionTypeEnum.PINTUAN, pintuan.getStoreId(), id);
				long sameNum = this.count(queryWrapper);
				// 当前时间段是否存在同类活动
				if (sameNum > 0) {
					throw new ServiceException(ResultCode.PROMOTION_SAME_ACTIVE_EXIST);
				}
			}
		}

		return super.updateStatus(ids, startTime, endTime);
	}

	/**
	 * 检查促销参数
	 *
	 * @param promotions
	 *            促销实体
	 */
	@Override
	public void checkPromotions(Pintuan promotions) {
		QueryWrapper<Pintuan> queryWrapper = PromotionTools.checkActiveTime(promotions.getStartTime(),
				promotions.getEndTime(), PromotionTypeEnum.PINTUAN, promotions.getStoreId(), promotions.getId());
		long sameNum = this.count(queryWrapper);
		// 当前时间段是否存在同类活动
		if (sameNum > 0) {
			throw new ServiceException(ResultCode.PROMOTION_SAME_ACTIVE_EXIST);
		}
		super.checkPromotions(promotions);
	}

	/**
	 * 更新促销商品信息
	 *
	 * @param promotions
	 *            促销实体
	 * @return 是否更新成功
	 */
	@Override
	public boolean updatePromotionsGoods(Pintuan promotions) {
		boolean result = super.updatePromotionsGoods(promotions);
		if (!PromotionsStatusEnum.CLOSE.name().equals(promotions.getPromotionStatus())
				&& PromotionsScopeTypeEnum.PORTION_GOODS.name().equals(promotions.getScopeType())
				&& promotions instanceof PintuanVO) {
			PintuanVO pintuanVO = (PintuanVO) promotions;
			this.updatePintuanPromotionGoods(pintuanVO);
			TimeTriggerMsg timeTriggerMsg = new TimeTriggerMsg(TimeExecuteConstant.PROMOTION_EXECUTOR,
					promotions.getEndTime().getTime(), promotions,
					DelayQueueTools.wrapperUniqueKey(DelayTypeEnums.PINTUAN_ORDER, (promotions.getId())),
					rocketmqCustomProperties.getPromotionTopic());
			// 发送促销活动开始的延时任务
			this.timeTrigger.addDelay(timeTriggerMsg);
		}
		if (promotions.getEndTime() == null && promotions.getStartTime() == null) {
			// 过滤父级拼团订单，根据父级拼团订单分组
			this.orderService.checkFictitiousOrder(promotions.getId(), promotions.getRequiredNum(),
					promotions.getFictitious());
		}
		return result;
	}

	/**
	 * 更新促销信息到商品索引
	 *
	 * @param promotions
	 *            促销实体
	 */
	@Override
	public void updateEsGoodsIndex(Pintuan promotions) {
		Pintuan pintuan = JSONUtil.parse(promotions).toBean(Pintuan.class);
		super.updateEsGoodsIndex(pintuan);
	}

	/**
	 * 当前促销类型
	 *
	 * @return 当前促销类型
	 */
	@Override
	public PromotionTypeEnum getPromotionType() {
		return PromotionTypeEnum.PINTUAN;
	}

	/**
	 * 根据订单信息，从中提取出拼团信息，设置拼团信息
	 *
	 * @param orders
	 *            订单列表
	 * @param pintuanShareVO
	 *            拼团信息
	 * @param skuId
	 *            商品skuId（用于获取拼团商品信息）
	 */
	private void setPintuanOrderInfo(List<Order> orders, PintuanShareVO pintuanShareVO, String skuId) {
		for (Order order : orders) {
			Member member = memberService.getById(order.getMemberId());
			PintuanMemberVO memberVO = new PintuanMemberVO(member);
			if (CharSequenceUtil.isEmpty(order.getParentOrderSn())) {
				memberVO.setOrderSn("");
				PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
				searchParams.setPromotionStatus(PromotionsStatusEnum.START.name());
				searchParams.setPromotionId(order.getPromotionId());
				searchParams.setSkuId(skuId);
				PromotionGoods promotionGoods = promotionGoodsService.getPromotionsGoods(searchParams);
				if (promotionGoods == null) {
					throw new ServiceException(ResultCode.PINTUAN_GOODS_NOT_EXIST_ERROR);
				}
				pintuanShareVO.setPromotionGoods(promotionGoods);
				Pintuan pintuanById = this.getById(order.getPromotionId());
				// 获取已参团人数
				this.setMemberVONum(memberVO, pintuanById.getRequiredNum(), order.getSn());
			}
			pintuanShareVO.getPintuanMemberVOS().add(memberVO);
		}
	}

	private void setMemberVONum(PintuanMemberVO memberVO, Integer requiredNum, String orderSn) {
		long count = this.orderService.queryCountByPromotion(PromotionTypeEnum.PINTUAN.name(),
				PayStatusEnum.PAID.name(), orderSn, orderSn);
		// 获取待参团人数
		long toBoGrouped = requiredNum - count;
		memberVO.setGroupNum(requiredNum);
		memberVO.setGroupedNum(count);
		memberVO.setToBeGroupedNum(toBoGrouped);
	}

	/**
	 * 更新记录的促销商品信息
	 *
	 * @param pintuan
	 *            拼团信息
	 */
	private void updatePintuanPromotionGoods(PintuanVO pintuan) {

		if (pintuan.getPromotionGoodsList() != null && !pintuan.getPromotionGoodsList().isEmpty()) {
			List<PromotionGoods> promotionGoods = PromotionTools.promotionGoodsInit(pintuan.getPromotionGoodsList(),
					pintuan, PromotionTypeEnum.PINTUAN);
			for (PromotionGoods promotionGood : promotionGoods) {
				if (goodsSkuService.getGoodsSkuByIdFromCache(promotionGood.getSkuId()) == null) {
					log.error("商品[" + promotionGood.getGoodsName() + "]不存在或处于不可售卖状态！");
					throw new ServiceException();
				}
				// 查询是否在同一时间段参与了拼团活动
				Integer count = promotionGoodsService.findInnerOverlapPromotionGoods(PromotionTypeEnum.SECKILL.name(),
						promotionGood.getSkuId(), pintuan.getStartTime(), pintuan.getEndTime(), pintuan.getId());
				// 查询是否在同一时间段参与了限时抢购活动
				count += promotionGoodsService.findInnerOverlapPromotionGoods(PromotionTypeEnum.PINTUAN.name(),
						promotionGood.getSkuId(), pintuan.getStartTime(), pintuan.getEndTime(), pintuan.getId());
				if (count > 0) {
					log.error("商品[" + promotionGood.getGoodsName() + "]已经在重叠的时间段参加了秒杀活动或拼团活动，不能参加拼团活动");
					throw new ServiceException(
							"商品[" + promotionGood.getGoodsName() + "]已经在重叠的时间段参加了秒杀活动或拼团活动，不能参加拼团活动");
				}
			}
			PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
			searchParams.setPromotionId(pintuan.getId());
			searchParams.setPromotionType(PromotionTypeEnum.PINTUAN.name());
			promotionGoodsService.deletePromotionGoods(searchParams);
			promotionGoodsService.saveOrUpdateBatch(promotionGoods);
		}
	}

}